package com.iqiju.guagua.redtone.video.service;


import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.iqiju.guagua.redtone.video.common.Results;
import com.iqiju.guagua.redtone.video.mapper.WxMiniUserMapper;
import com.iqiju.guagua.redtone.video.model.Jwt;
import com.iqiju.guagua.redtone.video.model.WxMiniApp;
import com.iqiju.guagua.redtone.video.model.WxMiniUser;
import com.iqiju.guagua.redtone.video.utils.JwtUtils;
import com.iqiju.guagua.redtone.video.utils.StringUtils;
import com.iqiju.guagua.redtone.video.vo.LoginVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;

@Slf4j
@Service
public class WxMiniUserService extends ServiceImpl<WxMiniUserMapper, WxMiniUser> {

    @Value("${http-url.access-token-url}")
    private String accessTokenUrl;

    @Value("${http-url.code-session-url}")
    private String codeSessionUrl;

    @Autowired
    private WxMiniAppService wxMiniAppService;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private IDService idService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    public Results<LoginVO> login(String wxMiniAppId, String code, String channel, String shareUserId) {
        if (StringUtils.isNull(wxMiniAppId)){
            log.error("参数 wxMiniAppId 为空");
            return Results.error("参数 wxMiniAppId 不能为空");
        }
        if (StringUtils.isNull(code)){
            log.error("参数 code 为空");
            return Results.error("参数 code 不能为空");
        }
        if (StringUtils.isNull(channel)){
            log.error("参数 channel 为空");
            return Results.error("参数 channel 不能为空");
        }
        if (StringUtils.isNull(shareUserId)){
            log.error("参数 shareUserId 为空");
            return Results.error("参数 shareUserId 不能为空");
        }

        WxMiniApp wxMiniApp = wxMiniAppService.selectById(Long.parseLong(wxMiniAppId));
        if (null == wxMiniApp){
            log.error("数据库中未配置小程序 wxMiniAppId={}", wxMiniAppId);
            return Results.paramError("请在数据库中配置小程序 wxMiniAppId="+wxMiniAppId);
        }

        /* 获取 openid session_key */
        JSONObject authCode2Session = getAuthCode2Session(wxMiniApp, code);
        if (null == authCode2Session){
            return Results.error("获取openid & session_key失败");
        }

        //用户openid
        String openid = authCode2Session.getString("openid");

        QueryWrapper<WxMiniUser> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("wx_mini_app_id",wxMiniAppId);
        userQueryWrapper.eq("openid",openid);
        List<WxMiniUser> userList = list(userQueryWrapper);

        WxMiniUser wxMiniUser = null;
        if (userList.isEmpty()){
            /* 保存到用户表 */
            wxMiniUser = new WxMiniUser();
            wxMiniUser.setId(idService.id());
            wxMiniUser.setWxMiniAppId(Long.valueOf(wxMiniAppId));
            wxMiniUser.setOpenid(openid);
            wxMiniUser.setCreateTime(new Date());
            wxMiniUser.setChannelId(channel);
            wxMiniUser.setShareUserId(Long.valueOf(shareUserId));
            boolean saveResult = save(wxMiniUser);
            log.info("注册到用户表结果=[{}]", saveResult);
            if (!saveResult){
                log.error("注册用户失败！wxMiniAppId={}  code={}  channel={}  shareUserId={}", wxMiniAppId,code,channel,shareUserId);
                return Results.error("注册用户失败！请检查参数并重试");
            }
        }else{
            wxMiniUser = userList.get(0);
        }

        /* 返回本地token */
        String jwt = null;
        try {
            jwt = loginSuccess(wxMiniUser);
            log.info("登录成功！");
            return Results.success(new LoginVO(jwt,wxMiniUser.getId()));
        } catch (Throwable e) {
            log.error("登录获取jwt异常！wxMiniAppId={}  code={}  channel={}  shareUserId={}", wxMiniAppId,code,channel,shareUserId);
            log.error(e.getMessage(), e);
            return Results.error("返回 token 异常");
        }
    }

    /** 初始化access token */
    private boolean setAccessToken(WxMiniApp wxMiniApp) {
        if (StringUtils.isNotNull(wxMiniApp.getAccessToken())) {
            Long expires = wxMiniApp.getExpires();
            if (expires > System.currentTimeMillis()){
                log.info("access_token 还未过期！");
                return true;
            }
            log.warn("access_token 已经过期！");
        }

        //删除缓存
        wxMiniAppService.delWxMiniAppKey(String.valueOf(wxMiniApp.getId()));

        String url = accessTokenUrl.replace("APPID",wxMiniApp.getAppId()).replace("APPSECRET",wxMiniApp.getAppSecret());

        JSONObject accessTokenObject = null;
        try {
            accessTokenObject = restTemplate.getForObject(url, JSONObject.class);
        } catch (RestClientException e) {
            log.error("setAccessToken 获取 accessTokenObject异常！appid=[{}]   appsecret=[{}]",wxMiniApp.getAppId(),wxMiniApp.getAppSecret());
            log.error(e.getMessage(), e);
            return false;
        }

        String accessToken = accessTokenObject.getString("access_token");
        if (StringUtils.isNotNull(accessToken)) {
            log.info("获取access_token 成功!  msg={}", accessTokenObject.toJSONString());
            long expire = accessTokenObject.getLong("expires_in");
            wxMiniApp.setAccessToken(accessToken);
            wxMiniApp.setExpires(expire*1000+System.currentTimeMillis());
            return wxMiniAppService.updateById(wxMiniApp);
        }else{
            String errCode = accessTokenObject.getString("errcode");
            String errMsg = accessTokenObject.getString("errmsg");
            log.error("获取access_token 失败! err_code={}     err_msg={}",errCode,errMsg);
            return false;
        }
    }

    /** 获取 openid session_key */
    private JSONObject getAuthCode2Session(WxMiniApp wxMiniApp, String code) {
        String url = codeSessionUrl.replace("APPID",wxMiniApp.getAppId()).replace("SECRET",wxMiniApp.getAppSecret()).replace("JSCODE",code);
        JSONObject codeObject = null;
        try {
            codeObject = restTemplate.getForObject(url, JSONObject.class);
        } catch (RestClientException e) {
            log.error("getAuthCode2Session 获取 codeObject异常！appid=[{}]   appsecret=[{}] code=[{}]",wxMiniApp.getAppId(),wxMiniApp.getAppSecret(), code);
            log.error(e.getMessage(), e);
            return null;
        }
        String openid = codeObject.getString("openid");
        if (StringUtils.isNotNull(openid)){
            log.info("获取 openid 成功！ codeObject=[{}]",codeObject.toJSONString());
            return codeObject;
        }else{
            Integer errcode = codeObject.getInteger("errcode");
            String errmsg = codeObject.getString("errmsg");
            log.error("获取 openid 失败  wxMiniAppId=[{}]  code=[{}]  errcode=[{}]  errmsg=[{}]",wxMiniApp.getId(),code,errcode,errmsg);
            return null;
        }
    }

    /** 生成jwt */
    public String loginSuccess(WxMiniUser user) throws Exception {
        // 获取登录成功信息
        user.setPassword(null);
        long now = System.currentTimeMillis();
        JSONObject payload = new JSONObject();
        payload.put("iss","REDTONE_VIDEO"); //签发人
        payload.put("aud",user.getId()); //受众
        payload.put("exp",now + JwtUtils.EXPIRE_TIME); //过期时间
        payload.put("nbf",now); //生效时间
        payload.put("iat",now); //签发时间
        payload.put("jti", user.getId()); //编号
        payload.put("sub","REDTONE_VIDEO_LOGIN"); //主题
        payload.put("user",user); //用户对象
        return new Jwt(payload.toJSONString()).toString();
    }


    private String getHaveAuthTodayKey(String userId){
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate now = LocalDate.now();
        String formatNow = dtf.format(now);
        return "IQIJU_MINI_APP_AUTH_"+formatNow+"_"+userId;
    }


    private String getWxUserKey(String id){
        return "IQIJU_MINI_APP_USER_"+id;
    }

}